/*
 *	Send flv file to rtmp server.
 *	@LIDECoolblue
 *	2015.07.03
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>

//#include <librtmp/rtmp_sys.h>
#include <librtmp/log.h>
#include <librtmp/rtmp.h>

/*
 * to build:
 *		gcc -Wall -o sendflvrtmp sendflvrtmp.c -lpthread -lrtmp -lssl -lcrypto -lz
 * */

#define HTON16(x)  ((x>>8&0xff)|(x<<8&0xff00))
#define HTON24(x)  ((x>>16&0xff)|(x<<16&0xff0000)|(x&0xff00))
#define HTON32(x)  ((x>>24&0xff)|(x>>8&0xff00)|\
		(x<<8&0xff0000)|(x<<24&0xff000000))
#define HTONTIME(x) ((x>>16&0xff)|(x<<16&0xff0000)|(x&0xff00)|(x&0xff000000))

int ReadU8(uint32_t *u8, FILE *fp);
int ReadU16(uint32_t *u16, FILE *fp);
int ReadU24(uint32_t *u24, FILE *fp);
int ReadU32(uint32_t *u32, FILE *fp);
int PeekU8(uint32_t *u8, FILE *fp);
int ReadTime(uint32_t *utime ,FILE *fp);

RTMP		*rtmp	=	NULL;
RTMPPacket	*packet	=	NULL;
char		*rtmpurl=	"rtmp://101.251.251.93:1935/myapp/test";
char	*flvfilename=	"../live.flv";

int ZINIT();
void ZCLEAR();

int main(){
	long	start		=	0;
	long	per_frame_time	=	0;
	long	last_time	=	0;
	int		bnext_iskey	=	1;
	RTMP_LogLevel	lvl	=	RTMP_LOGINFO;
	FILE	*fp			=	NULL;

	if(!ZINIT()){
		printf("Init socket Err\n");
		return -1;
	}

	RTMP_LogSetLevel(lvl);

	rtmp	=	RTMP_Alloc();
	RTMP_Init(rtmp);
	rtmp->Link.timeout	=	5;
	packet	=	(RTMPPacket*)malloc(sizeof(RTMPPacket));
	memset(packet, 0, sizeof(RTMPPacket));
	RTMPPacket_Alloc(packet, 1024 * 64);
	RTMPPacket_Reset(packet);

	RTMP_SetupURL(rtmp, rtmpurl);
	RTMP_EnableWrite(rtmp);

	if(!RTMP_Connect(rtmp, NULL)){
		printf("Connect Err\n");
		ZCLEAR();
		return -1;
	}

	if(!RTMP_ConnectStream(rtmp, 0)){
		printf("ConnectStream Err\n");
		ZCLEAR();
		return -1;
	}

	packet->m_hasAbsTimestamp	=	0;
	packet->m_nChannel			=	0x04;
	packet->m_nInfoField2		=	rtmp->m_stream_id;

	fp	=	fopen(flvfilename, "rb");
	if(fp == NULL){
		printf("Open file:%s Err\n", flvfilename);
		ZCLEAR();
		return -1;
	}

	printf("rtmpurl:%s\nflvfilename:%s\nsend data ...\n", rtmpurl, flvfilename);

	fseek(fp, 9, SEEK_SET);
	fseek(fp, 4, SEEK_CUR);
	start	=	time(NULL) - 1;
	per_frame_time	=	0;
	
	while(TRUE){
		uint32_t	type		=	0;
		uint32_t	datalength	=	0;
		uint32_t	timestamp	=	0;
		uint32_t	streamid	=	0;
		uint32_t	alldatalength=	0;
		
		if((time(NULL) - start)<(per_frame_time / 1000)){
	//	if(((time(NULL)-start) < (per_frame_time / 1000)) && bnext_iskey){
			if(per_frame_time > last_time){
				printf("TimeStamp:%8lu ms\n", per_frame_time);
				last_time	=	per_frame_time;
			}
			sleep(1);
			continue;
		}

		if(!ReadU8(&type, fp))
			break;
		if(!ReadU24(&datalength, fp))
			break;
		if(!ReadTime(&timestamp, fp))
			break;
		if(!ReadU24(&streamid, fp))
			break;
		if(type != 0x08 && type != 0x09){
			fseek(fp, datalength + 4, SEEK_CUR);
			continue;
		}
		if(fread(packet->m_body, 1, datalength, fp) != datalength)
			break;
		packet->m_headerType	=	RTMP_PACKET_SIZE_MEDIUM;
		packet->m_nTimeStamp	=	timestamp;
		packet->m_packetType	=	type;
		packet->m_nBodySize		=	datalength;

		if(!RTMP_IsConnected(rtmp)){
			printf("rtmp is not connect\n");
			break;
		}

		if(!RTMP_SendPacket(rtmp, packet, 0)){
			printf("SendPacket err\n");
			break;
		}

		if(!ReadU32(&alldatalength, fp))
			break;

		per_frame_time	=	timestamp;

		bnext_iskey		=	0;
		if(!PeekU8(&type, fp))
			break;
			
		if(type	== 0x09){
			if(fseek(fp, 11, SEEK_CUR) != 0)
				break;

			if(!PeekU8(&type, fp)){
				break;
			}

			if(type == 0x17){
				bnext_iskey		=	1;
			}

			fseek(fp, -11, SEEK_CUR);
		}

	}	

	printf("\nSend Data Over\n");

	fclose(fp);

	ZCLEAR();
	return 0;

}

int ZINIT(){
	return 1;
}

void ZCLEAR(){
	if(rtmp != NULL){
		RTMP_Close(rtmp);
		RTMP_Free(rtmp);
		rtmp	=	NULL;
	}

	if(packet != NULL){
		RTMPPacket_Free(packet);
		free(packet);
		packet	=	NULL;
	}
}

int ReadU8(uint32_t *u8, FILE *fp){
	if(fread(u8, 1, 1, fp) != 1){
		return 0;
	}
	return 1;
}

int ReadU16(uint32_t *u16, FILE *fp){
	if(fread(u16, 2, 1, fp) != 1)
		return 0;

	*u16	=	HTON16(*u16);

	return 1;
}

int ReadU24(uint32_t *u24, FILE *fp){
	if(fread(u24, 3, 1, fp) != 1)
		return 0;

	*u24	=	HTON24(*u24);

	return 1;
}

int ReadU32(uint32_t *u32, FILE *fp){
	if(fread(u32, 4, 1, fp) != 1)
		return 0;

	*u32	=	HTON32(*u32);
	return 1;
}

int PeekU8(uint32_t *u8, FILE *fp){
	if(fread(u8, 1, 1, fp) != 1){
		return 0;
	}

	fseek(fp, -1, SEEK_CUR);
	return 1;
}

int ReadTime(uint32_t *utime, FILE *fp){
	if(fread(utime, 4, 1, fp) != 1)
		return 0;
	
	*utime	=	HTONTIME(*utime);

	return 1;
}
